const apiConfig = (apiJson) => {
  let tags = [];
  if (apiConfig.tags) {
    tags = apiJson.tags || [];
  } else {
    let p = apiJson.paths;
    if (p) {
      let pathKeys = Object.keys(p);
      pathKeys.forEach((k) => {
        let pathItem = p[k];
        let itemKeys = Object.keys(pathItem);
        let method = itemKeys[0];
        let item = pathItem[method];
        let tag = item.tags ? item.tags[0] : null;
        let t = tags.find((e) => e.name === tag);
        if (!t && tag != null) {
          tags.push({
            name: tag,
            description: item.description,
          });
        }
      });
    }
  }
  const paths = apiJson.paths || {};
  return {
    tags,
    paths,
    definitions: apiJson.definitions || {},
  };
};

const apiMapInit = (tags) => {
  const m = {};
  tags.map((tag) => {
    if (tag.name !== "") {
      m[tag.name] = [];
    }
  });
  return m;
};

const apiMap = (apiPrefix = "", paths, apiMap) => {
  const m = JSON.parse(JSON.stringify(apiMap));
  const dict = {
    新增: {
      prefix: "add",
      label: "新增",
    },

    添加: {
      prefix: "add",
      label: "添加",
    },

    修改: {
      prefix: "update",
      label: "修改",
    },

    删除: {
      prefix: "del",
      label: "删除",
    },

    详情: {
      prefix: "detail",
      label: "详情",
    },
    列表: {
      prefix: "list",
      label: "列表",
    },
    分页: {
      prefix: "pagination",
      label: "分页",
    },
    记录: {
      prefix: "record",
      label: "记录",
    },
    查询: {
      prefix: "serach",
      label: "分页",
    },
    测试: {
      prefix: "test",
      label: "测试",
    },
    get: {
      prefix: "get",
      label: "新增",
    },
    post: {
      prefix: "update",
      label: "修改",
    },
    put: {
      prefix: "put",
      label: "修改",
    },
    delete: {
      prefix: "del",
      label: "删除",
    },
  };
  // const dictKeys = Object.keys(dict);
  const keyword = [
    "export",
    "break",
    "else",
    "new",
    "var",
    "case",
    "finally",
    "return",
    "void",
    "catch",
    "for",
    "switch",
    "while",
    "continue",
    "function",
    "this",
    "with",
    "default",
    "if",
    "throw",
    "delete",
    "in",
    "try",
    "do",
    "instranceof",
    "typeof",
  ];
  // 分类所有api
  Object.keys(paths).forEach((path) => {
    const item = paths[path];
    let keyList = ["get", "post", "put", "delete"].concat(Object.keys(item));
    let methodKey = keyList.filter((item, index, self) => {
      return self.indexOf(item) !== index;
    });
    if (methodKey.length > 0) {
      const method = (methodKey[0] || "").toLocaleLowerCase();
      const tagName = item[method].tags[0] || ""; // 所属文件夹
      const summary = item[method].summary
        ? `${tagName} : ${item[method].summary}`
        : tagName; // 接口简单描述
      const params = item[method].parameters || [];
      let pathList = path.split("/");
      let lastPath;
      if (!pathList[pathList.length - 1].includes("{")) {
        // 如果 path 不使用 路径参数, 使用路径最后的名字命名 api 函数名称
        lastPath = pathList[pathList.length - 1]
          ? pathList[pathList.length - 1].replace(new RegExp("-", "g"), "")
          : "";
      } else {
        lastPath = pathList[pathList.length - 2]
          ? pathList[pathList.length - 2].replace(new RegExp("-", "g"), "")
          : "";
      }
      // let key = dictKeys.find((key) => {
      //   let s = item[method].summary;
      //   if (s) {
      //     return s.includes(key);
      //   } else {
      //     return null;
      //   }
      // });
      let methodType = dict[method];
      let tagList = m[tagName];
      let apiName = lastPath.replace(lastPath[0], lastPath[0]);
      tagList.push({
        summary,
        path: apiPrefix + path,
        params,
        method,
        apiName:
          keyword.indexOf(apiName) !== -1
            ? methodType.prefix +
              lastPath.replace(lastPath[0], lastPath[0].toUpperCase())
            : lastPath.replace(lastPath[0], lastPath[0]),
        // apiName:
        //   methodType.prefix +
        //   lastPath.replace(lastPath[0], lastPath[0].toUpperCase()),
      });
    }
  });
  return m;
};

const apiDescriptions = (config) => {
  // 添加 参数 描述
  let paramsDoc = "";
  config.params.forEach((p) => {
    let type;
    if (p.type) {
      type = p.type;
    } else {
      if (p.schema) {
        if (p.schema.originalRef) {
          type = "object";
        } else {
          if (p.schema.type) {
            type = p.schema.type;
          } else {
            type = "";
          }
        }
      } else {
        type = "";
      }
    }
    paramsDoc +=
      "\r\n" +
      `* @param { ${type} } ${p.name} - ${
        p.description
      } ( required: ${p.required || false} )`;
  });
  return { desc: `${config.summary}${paramsDoc}` };
};

const apiTemplate = ({ requestName = "request", config }) => {
  // params in path, query, body
  let { params, dataConfig, pathParams } = apiParams(config);
  let { desc } = apiDescriptions(config);
  const requestConfig = {
    method: `'${config.method}'`,
    path: `${config.path}`,
  };
  let tPath = "`" + `${requestConfig.path}` + "`";
  if (pathParams.length > 0) {
    // 替换路径上的参数为模板语法
    tPath = tPath.replace(/{/g, "${");
  }
  let lengthFlag = params.split(',').length > 3 // 参数大于3个
  let t = `/*
${desc}
*/
export const ${config.apiName} = (${lengthFlag ? 'params' : params}) => {
    return ${requestName}({
        method: ${requestConfig.method},
        url: ${pathParams.length > 0 ? tPath : `'${requestConfig.path}'`},${
    dataConfig.params ? `params: { ${lengthFlag ? '...params': dataConfig.params}},` : ""
  }${dataConfig.data ? `data: { ${lengthFlag ? '...params': dataConfig.data} },` : ""}
    })
}

`;
  return t;
};

const apiParams = (config) => {
  const { path, query, body } = apiConfigParams(config);
  let dataConfig = {};
  let params = "";
  if (path.length > 0) {
    params += path.join(", ");
  }

  if (query.length > 0) {
    let q = query.join(", ");
    dataConfig.params = `${q}`;
    params += q;
  }
  if (body.length > 0) {
    let d = body.join(", ");
    dataConfig.data = `${d}`;
    params += d;
  }

  return { params, dataConfig, pathParams: path };
};

const apiConfigParams = (config) => {
  let list = config.params;
  let query = [];
  let body = [];
  let path = [];

  list.forEach((p) => {
    let paramName = p.name;
    let i = p.in;
    if (i === "path") {
      path.push(paramName);
    } else if (i === "query") {
      query.push(paramName);
    } else if (i === "body") {
      body.push(paramName);
    }
  });
  return { path, query, body };
};

const apiFile = (requestName, apiconfig) => {
  let apiList = [];
  let keys = Object.keys(apiconfig);
  keys.forEach((k) => {
    let list = apiconfig[k];
    if (list) {
      apiList.push([
        [k],
        [...list.map((config) => apiTemplate({ requestName, config }))],
      ]);
    }
  });

  return apiList;
};

const objectProperties = (definitions, label = false) => {
  let type = ["string", "boolean", "integer", "number", "object"];
  let value = [`''`, false, null, null, "{}"];
  let keys = Object.keys(definitions);
  let data = "";
  let dataLabel = "";
  keys.forEach((k) => {
    let item = definitions[k];
    let oKey = k;
    // 判断 id 只获取实体类
    if (item.properties && Object.prototype.hasOwnProperty.call(item.properties, "id")) {
      if (item.type === "object") {
        let properties = item.properties;
        let propKeys = Object.keys(properties);
        let o = "";
        let m = "";
        propKeys.forEach((pkey) => {
          let pItem = properties[pkey];
          let index = type.findIndex((e) => e === pItem.type);
          if (index !== -1) {
            o += `'${pkey}': ${value[index]}, // ${pItem.description}\r\n`;
          } else {
            o += `'${pkey}': null,\r\n`;
          }
          m += `'${pkey}': { prop: '${pkey}', label: '${pItem.description}' }, // ${pItem.description}\r\n`;
        });
        let obj = `{${o}}`;
        data += `'${oKey.slice(0).toLocaleLowerCase() + oKey.slice(1)}': ${obj},
                `;
        if (label === true) {
          let objLabel = `{${m}}`;
          dataLabel += `'${oKey.slice(0).toLocaleLowerCase() +
            oKey.slice(1)}': ${objLabel},
                  `;
        }
      }
    }
  });
  let item = {
    modelData: `{${data}}`,
  };
  if (label === true) {
    item.dataLabel = `{${dataLabel}}`;
  }
  return item;
};

const service = async ({
  requestName = "request",
  apiPath,
  json = null,
  apiPrefix = "",
  importPath,
  modelLabel = false,
}) => {
  // const apiJson = require(apiPath);
  let apiJson = {};
  if (json) {
    apiJson = json;
  } else {
    apiJson = await fetch(apiPath).then((res) => res.json());
  }
  const { tags, paths, definitions } = apiConfig(apiJson);
  let m = apiMapInit(tags);
  let data = apiMap(apiPrefix, paths, m);
  let list = apiFile(requestName, data);
  let { modelData, dataLabel } = objectProperties(definitions, modelLabel);
  // const fs = require("fs");
  const beautify = require("js-beautify").js_beautify;
  try {
    let option = {
      indent_size: 4,
      space_in_empty_paren: true,
    };
    let allData = {
      api: {},
    };
    list.forEach((file) => {
      let fileName = file[0];
      let requestPath = importPath ? importPath + "\r\n\r\n" : "";
      let fileContent = requestPath + file[1].join("");
      let formatContent = beautify(fileContent, option);
      // fs.writeFileSync(`../${fileName}.js`, formatContent, {
      //   encoding: "utf8",
      // });
      allData.api[fileName] = formatContent;
    });
    const formatModelData = beautify(modelData, option);
    // fs.writeFileSync("../model.js", formatModelData, {
    //   encoding: "utf8",
    // });
    allData.model = formatModelData;
    if (modelLabel === true) {
      const formatModelLabelData = beautify(dataLabel, option);
      // fs.writeFileSync("../modelable.js", formatModelLabelData, {
      //   encoding: "utf8",
      // });
      allData.modelLabel = formatModelLabelData;
    }
    return allData;
  } catch (err) {
    console.error(err);
  }
};

import makeForm from "./form";
export { service, makeForm };
